package com.xposed.xposedinit.xposedFiles

import android.content.Context
import android.os.Bundle
import de.robv.android.xposed.*
import de.robv.android.xposed.callbacks.XC_LoadPackage
import java.lang.reflect.Modifier


class XposedInit : IXposedHookLoadPackage {
    private val pageName = "com.xposed.xposedinit"
    private val className = "$pageName.MainActivity"
    private val methodName = "isModuleActive"

    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
        XposedBridge.log("--------------------------- XposedMainInit handleLoadPackage 已执行 -------------------------------------------------");
        returnConstant(lpparam, pageName, className, methodName, true)
        hookMethodStack(lpparam,"android.telephony.TelephonyManager","getDeviceId")

        hook_method(
            "android.telephony.TelephonyManager",
            lpparam!!.classLoader,
            "getDeviceId",
            object : XC_MethodHook() {
                override fun beforeHookedMethod(param: MethodHookParam?) {
                    super.beforeHookedMethod(param)
                    XposedBridge.log("===============thisObject>${param!!.thisObject.toString()}")
                    Exception().stackTrace
                }

                override fun afterHookedMethod(param: MethodHookParam?) {
                    super.afterHookedMethod(param)
                    val obj = param!!.result
                    XposedBridge.log("===============imei>$obj")
                    //替换返回值
                    param.result = "hahahahhahahah"
                }
            })
    }

    /**
     * @param lpparam 解析器
     * @param pageName 劫持的包名
     * @param methodName 劫持的方法名称
     * @param Object 修改返回的值
     */
    private fun returnConstant(
        lpparam: XC_LoadPackage.LoadPackageParam?,
        pageName: String,
        className: String,
        methodName: String,
        result: Any
    ) {
        if (lpparam != null) {
            // Xposed模块自检测
            if (lpparam.packageName.equals(pageName)) {
                XposedHelpers.findAndHookMethod(
                    className,                                          //类名
                    lpparam.classLoader,                                //class 加载器
                    methodName,                                         //方法名称
                    XC_MethodReplacement.returnConstant(result)         //修改方法返回值
                )
            }
        }
    }

    /**
     * 检测方法调用堆栈
     * @param className hook className
     * @param methodName Hook 方法
     */
    private fun hookMethodStack(
        lpparam: XC_LoadPackage.LoadPackageParam?,
        className: String,
        methodName: String
    ) {
        val clazz = XposedHelpers.findClass(className, lpparam!!.classLoader);
        XposedHelpers.findAndHookMethod(clazz, methodName, object : XC_MethodHook() {
            @Override
            override fun beforeHookedMethod(param: MethodHookParam?) {
                super.beforeHookedMethod(param);
                XposedBridge.log("zzyy----hook到getHardwareAddress方法");
                Exception().stackTrace;
                val ex = Throwable()
                val stackElements = ex.stackTrace
                for ((index, emit) in stackElements.withIndex()) {
                    XposedBridge.log(
                        "Dump Stack" + index + " 堆栈class名称: " + stackElements[index].className
                                + "||文件名称：" + stackElements[index].fileName
                                + "||行数：" + stackElements[index].lineNumber
                                + "||方法名称：" + stackElements[index].methodName
                    );
                }
            }
        });
    }


    private fun findAndhookMethod(
        lpparam: XC_LoadPackage.LoadPackageParam?,
        className: String,
        methodName: String
    ) {
        XposedHelpers.findAndHookMethod(
            className,
            lpparam!!.classLoader,
            methodName,
            Bundle::class.java,
            object : XC_MethodHook() {
                override fun beforeHookedMethod(param: MethodHookParam?) {
                    super.beforeHookedMethod(param)
                    XposedBridge.log("==========>Hook 方法前<===============")
                    var context = param!!.args[0] as Context
                    var classLoader = context.classLoader
                }

                override fun afterHookedMethod(param: MethodHookParam?) {
                    super.afterHookedMethod(param)
                    XposedBridge.log("==========>Hook 方法后<===============")
                }
            })
    }


    /**
     *
     */
    private fun hook_method(
        className: String, classLoader: ClassLoader, methodName: String,
        vararg parameterTypesAndCallback: Any
    ) {
        try {
            XposedHelpers.findAndHookMethod(
                className,
                classLoader,
                methodName,
                *parameterTypesAndCallback
            )
        } catch (e: Exception) {
            XposedBridge.log(e)
        }
    }

    /**
     * 通过反射来获取方法
     */
    private fun hook_methods(className: String, methodName: String, xmh: XC_MethodHook) {
        try {
            val clazz = Class.forName(className)
            for (method in clazz.declaredMethods) if (method.name.equals(methodName)
                && !Modifier.isAbstract(method.modifiers)
                && Modifier.isPublic(method.modifiers)
            ) {
                XposedBridge.hookMethod(method, xmh)
            }
        } catch (e: Exception) {
            XposedBridge.log(e)
        }
    }
}